/*
 * Copyright 2007 Matt Jensen
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.jtell.spring;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.jtell.config.ConfigurationSource;
import org.jtell.config.xml.XmlConfigurationSource;
import org.jtell.config.annotation.AnnotationConfigurationSource;

/**
 * <p>
 * <code>ContextBeanDefinitionParser</code> is an implementation of the Spring {@link BeanDefinitionParser} interface
 * which is used to create and configure a JTell context when a <code>&lt;jtell:context ...&gt;</code> element is used
 * in a bean definition file.
 * </p>
 */
public class ContextBeanDefinitionParser extends AbstractBeanDefinitionParser
{
    private static Log LOG = LogFactory.getLog(ContextBeanDefinitionParser.class);

    /**
     * <p>
     * Construct a {@link ContextBeanDefinitionParser} instance.
     * </p>
     */
    public ContextBeanDefinitionParser()
    {
        super();
    }

    /* inherit javadoc */
    @Override
    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext)
    {
        // Create the root bean definition for the context factory bean.
        final AbstractBeanDefinition contextFactoryBeanDefinition =
                new RootBeanDefinition(JTellContextFactoryBean.class);
        final MutablePropertyValues propertyValues = contextFactoryBeanDefinition.getPropertyValues();
        final BeanDefinitionRegistry registry = parserContext.getRegistry();

        // Apply the appropriate configuration type if one is specified.
        final String configurationType = element.getAttribute("configuration-type");
        if (StringUtils.hasText(configurationType))
        {
            // Create a configuration source of the configured type.
            final ConfigurationSource configurationSource;
            if ("annotation".equals(configurationType))
            {
                configurationSource = new AnnotationConfigurationSource();
            }
            else if ("xml".equals(configurationType))
            {
                configurationSource = new XmlConfigurationSource();
            }
            else
            {
                throw new IllegalArgumentException(String.format(
                        "The [configuration-type] value [%s] is not recognized, use one of: [annotation], [xml].",
                        configurationType));
            }

            // Attach the configuration source to the bean definition.
            propertyValues.addPropertyValue("configurationSource", configurationSource);
            if (LOG.isDebugEnabled())
            {
                LOG.debug(String.format("Attaching configuration source [%s].", configurationSource));
            }
        }

        // Return the context factory bean definition.
        if (LOG.isDebugEnabled())
        {
            LOG.debug(String.format("Returning new bean definition [%s].", contextFactoryBeanDefinition));
        }
        return contextFactoryBeanDefinition;
    }
}
